<?php
/**
 * @link https://www.len168.com
 * @copyright Copyright (c) 2020/9/21 len168.com
 * @author toshcn <toshcn@foxmail.com>
 */
namespace common\models;

use Yii;
use yii\base\Model;
use yii\helpers\FileHelper;

/**
 * Upload form
 */
class UploadForm extends Model
{
    /** @var object 图片文件 */
    public $imageFile;

    /** @var object 多个图片文件 */
    public $imageFiles;

    /** @var object 视频文件 */
    public $videoFile;

    /** @var object 音频文件 */
    public $audioFile;

    /** @var object 文件 */
    public $file;

    /**
     * 场景
     * @return array
     */
    public function scenarios()
    {
        $scenarios = parent::scenarios();
        $scenarios['image'] = ['imageFile'];
        $scenarios['video'] = ['videoFile'];
        $scenarios['audio'] = ['audioFile'];
        $scenarios['file'] = ['file'];
        return $scenarios;
    }

    /**
     * {@inheritdoc}
     */
    public function rules()
    {
        return [
            [
                ['file'], 'file', 'skipOnEmpty' => false,
                'extensions' => Yii::$app->config->getItem('uploadFileExt'),
                'maxSize' => Yii::$app->config->getItem('uploadFileMaxSize') * 1048576,
                'on' => 'file'
            ],
            [
                ['imageFile'], 'file', 'skipOnEmpty' => false,
                'extensions' => Yii::$app->config->getItem('uploadImageExt'),
                'maxSize' => Yii::$app->config->getItem('uploadImageMaxSize') * 1048576,
                'on' => 'image'
            ],
            [
                ['videoFile'], 'file', 'skipOnEmpty' => false,
                'extensions' => Yii::$app->config->getItem('uploadVideoExt'),
                'maxSize' => Yii::$app->config->getItem('uploadVideoMaxSize') * 1048576,
                'on' => 'video'
            ],
            [
                ['audioFile'], 'file', 'skipOnEmpty' => false,
                'extensions' => Yii::$app->config->getItem('uploadAudioExt'),
                'maxSize' => Yii::$app->config->getItem('uploadAudioMaxSize') * 1048576,
                'on' => 'audio'
            ]
        ];
    }

    /**
     * 上传普通图片
     * @param int $uid 上传用户ID
     * @return mixed
     * @throws \yii\base\InvalidConfigException
     */
    public function uploadImage($uid = 0)
    {
        if (!empty($this->imageFile)) {
            // 如果文件后缀与文件mine类型不同，更新文件后缀
            $mimeType = FileHelper::getMimeType($this->imageFile->tempName, null, false);
            $old = explode('/', $this->imageFile->type);
            $new = explode('/', $mimeType);
            if ($new[1] == 'jpeg') $new[1] = 'jpg';
            $this->imageFile->type = $mimeType;
            $this->imageFile->name = str_replace('.' . $old[1], '.' . $new[1], $this->imageFile->name);
            if ($this->validate()) {
                // 计算文件md5值
                $md5 = md5_file($this->imageFile->tempName);
                // 返回已有记录
                if ($record = $this->hasRecord($md5)) {
                    return $record;
                }
                // 上传
                $res = Yii::$app->oss->upload($this->imageFile, $uid);
                if ($res['code'] == 1) {
                    // 保存到附件表
                    if ($data = $this->saveAt($res['data'], $uid, $md5, Attachment::IMAGE, $this->imageFile->size)) {
                        return $data;
                    }
                    // 保存失败删除
                    Yii::$app->oss->delete($res['data']['url']);
                }
                $this->addError(static::getFieldName(Attachment::IMAGE), $res['message']);
            }
        }
        return false;
    }

    /**
     * 上传视频
     * @param int $uid 上传用户ID
     * @return mixed
     * @throws \yii\base\InvalidConfigException
     */
    public function uploadVideo($uid = 0)
    {
        if (!empty($this->videoFile)) {
            // 如果文件后缀与文件mine类型不同，更新文件后缀
            $mimeType = FileHelper::getMimeType($this->videoFile->tempName, null, false);
            $old = explode('/', $this->videoFile->type);
            $new = explode('/', $mimeType);
            if ($new[1] == 'quicktime') $new[1] = 'mov';
            $this->videoFile->type = $mimeType;
            $this->videoFile->name = str_replace('.' . $old[1], '.' . $new[1], $this->videoFile->name);
            if ($this->validate()) {
                // 计算文件md5值
                $md5 = md5_file($this->videoFile->tempName);
                // 返回已有记录
                if ($record = $this->hasRecord($md5)) {
                    return $record;
                }
                // 上传
                $res = Yii::$app->oss->upload($this->videoFile, $uid);
                if ($res['code'] == 1) {
                    // 保存到附件表
                    if ($data = $this->saveAt($res['data'], $uid, $md5, Attachment::VIDEO, $this->videoFile->size)) {
                        return $data;
                    }
                    // 保存失败删除
                    Yii::$app->oss->delete($res['data']['url']);
                }
                $this->addError(static::getFieldName(Attachment::VIDEO), $res['message']);
            }
        }
        return false;
    }

    /**
     * 上传音频
     * @param int $uid 上传用户ID
     * @return mixed
     * @throws \yii\base\InvalidConfigException
     */
    public function uploadAudio($uid = 0)
    {
        if (!empty($this->audioFile)) {
            // 如果文件后缀与文件mine类型不同，更新文件后缀
            $mimeType = FileHelper::getMimeType($this->audioFile->tempName, null, false);
            $old = explode('/', $this->audioFile->type);
            $new = explode('/', $mimeType);
            $this->audioFile->type = $mimeType;
            $this->audioFile->name = str_replace('.' . $old[1], '.' . $new[1], $this->audioFile->name);
            if ($this->validate()) {
                // 计算文件md5值
                $md5 = md5_file($this->audioFile->tempName);
                // 返回已有记录
                if ($record = $this->hasRecord($md5)) {
                    return $record;
                }
                // 上传
                $res = Yii::$app->oss->upload($this->audioFile, $uid);
                if ($res['code'] == 1) {
                    // 保存到附件表
                    if ($data = $this->saveAt($res['data'], $uid, $md5, Attachment::AUDIO, $this->audioFile->size)) {
                        return $data;
                    }
                    // 保存失败删除
                    Yii::$app->oss->delete($res['data']['url']);
                }
                $this->addError(static::getFieldName(Attachment::AUDIO), $res['message']);
            }
        }
        return false;
    }

    /**
     * 上传文件
     * @param int $uid 上传用户ID
     * @return mixed
     * @throws \yii\base\InvalidConfigException
     */
    public function uploadFile($uid = 0)
    {
        if (!empty($this->file)) {
            // 如果文件后缀与文件mine类型不同，更新文件后缀
            $mimeType = FileHelper::getMimeType($this->file->tempName, null, false);
            $old = explode('/', $this->file->type);
            $new = explode('/', $mimeType);
            if ($new[1] == 'jpeg') $new[1] = 'jpg';
            if ($new[1] == 'quicktime') $new[1] = 'mov';
            $this->file->type = $mimeType;
            $this->file->name = str_replace('.' . $old[1], '.' . $new[1], $this->file->name);

            if ($this->validate()) {
                // 计算文件md5值
                $md5 = md5_file($this->file->tempName);
                // 返回已有记录
                if ($record = $this->hasRecord($md5)) {
                    return $record;
                }
                // 上传
                $res = Yii::$app->oss->upload($this->file, $uid);
                if ($res['code'] == 1) {
                    $iExt = Yii::$app->config->getItem('uploadImageExt');
                    $vExt = Yii::$app->config->getItem('uploadVideoExt');
                    $aExt = Yii::$app->config->getItem('uploadAudioExt');
                    if (in_array($new[1], $iExt)) {
                        $fType = Attachment::IMAGE;
                    } else if (in_array($new[1], $vExt)) {
                        $fType = Attachment::VIDEO;
                    } else if (in_array($new[1], $aExt)) {
                        $fType = Attachment::AUDIO;
                    } else {
                        $fType = Attachment::OTHER;
                    }
                    // 保存到附件表
                    if ($data = $this->saveAt($res['data'], $uid, $md5, $fType, $this->file->size)) {
                        return $data;
                    }
                    // 保存失败删除
                    Yii::$app->oss->delete($res['data']['url']);
                }
                $this->addError(static::getFieldName(Attachment::OTHER), $res['message']);
            }
        }
        return false;
    }

    /**
     * 上传头像图片
     * @param int $uid 上传用户ID
     * @return mixed
     * @throws \yii\base\InvalidConfigException
     */
    public function uploadAvatar($uid = 0)
    {
        if (!empty($this->imageFile)) {
            // 如果文件后缀与文件mine类型不同，更新文件后缀
            $mimeType = FileHelper::getMimeType($this->imageFile->tempName, null, false);
            $new = explode('/', $mimeType);
            if ($new[1] == 'jpeg') $new[1] = 'jpg';
            $this->imageFile->type = $mimeType;
            $this->imageFile->name = $this->imageFile->name . '.' . $new[1];
            // 如果文件后缀与文件mine类型不同，更新文件后缀
            if ($this->validate()) {
                // 计算文件md5值
                $md5 = md5_file($this->imageFile->tempName);
                // 返回已有记录
                if ($record = $this->hasRecord($md5)) {
                    return $record;
                }
                // 上传
                $res = Yii::$app->oss->upload($this->imageFile, $uid, true);
                if ($res['code'] == 1) {
                    // 保存到附件表
                    if ($data = $this->saveAt($res['data'], $uid, $md5, Attachment::AVATAR, $this->imageFile->size)) {
                        return $data;
                    }
                    // 保存失败删除
                    Yii::$app->oss->delete($res['data']['url']);
                }
                $this->addError(static::getFieldName(Attachment::AVATAR), $res['message']);
            }
        }
        return false;
    }

    /**
     * 上传第三方账号头像图片
     * @param int $uid 上传用户ID
     * @return mixed
     * @throws \yii\base\InvalidConfigException
     */
    public function uploadOauthAvatar($uid = 0)
    {
        if (!empty($this->imageFile)) {
            // 如果文件后缀与文件mine类型不同，更新文件后缀
            $mimeType = FileHelper::getMimeType($this->imageFile->tempName, null, false);
            $new = explode('/', $mimeType);
            if ($new[1] == 'jpeg') $new[1] = 'jpg';
            $this->imageFile->type = $mimeType;
            $this->imageFile->name = $this->imageFile->name . '.' . $new[1];
            // 如果文件后缀与文件mine类型不同，更新文件后缀
            if ($this->validate()) {
                // 计算文件md5值
                $md5 = md5_file($this->imageFile->tempName);
                // 返回已有记录
                if ($record = $this->hasRecord($md5)) {
                    return $record;
                }
                // 上传 手动删除临时文件
                $res = Yii::$app->oss->upload($this->imageFile, $uid, true, false);
                @unlink($this->imageFile->tempName);
                if ($res['code'] == 1) {
                    // 保存到附件表
                    if ($data = $this->saveAt($res['data'], $uid, $md5, Attachment::AVATAR, $this->imageFile->size)) {
                        return $data;
                    }
                    // 保存失败删除
                    Yii::$app->oss->delete($res['data']['url']);
                }
                $this->addError(static::getFieldName(Attachment::AVATAR), $res['message']);
            }
        }
        return false;
    }

    /**
     * 检测上传文件是否已上传过，如已上传，返回已有记录
     * @param $md5 string 上传文件md5值
     * @return array|bool
     */
    private function hasRecord($md5)
    {
        if ($md5 && ($record =  Attachment::findOne(['file_md5' => $md5]))) {
            // 已上传 返回数据库中记录
            return [
                'id' => $record->id,
                'url' => $record->file_path,
                'size' => $record->file_size,
                'fileName' => $record->file_name,
                'fullName' => $record->file_name . '.' . $record->file_suffix,
                'fileExt' => $record->file_suffix
            ];
        }
        return false;
    }

    /**
     * 保存到数据库
     * @param $data array 上传数据
     * @param $uid integer 上传用户
     * @param $md5 string 上传文件md5
     * @param int $type 上传文件类型
     * @param int $size 上传文件大小
     * @return array|bool
     */
    private function saveAt(&$data, $uid, $md5, $type = Attachment::OTHER, $size = 0)
    {
        $model = new Attachment();
        $model->uid = $uid;
        $model->file_md5 = $md5;
        $model->file_type = $type;
        $model->file_name = $data['fileName'];
        $model->file_path = $data['path'];
        $model->file_size = $size;
        $model->file_suffix = $data['fileExt'];
        $model->save_handler = $data['handler'];
        $model->created_at = $model->updated_at = date('Y-m-d H:i:s');
        if ($model->save()) {
            return [
                'id' => $model->id,
                'uid' => $uid,
                'url' => $model->file_path,
                'size' => $model->file_size,
                'fileName' => $model->file_name,
                'saveHandler' => $model->save_handler,
                'fileType' => $type,
                'fullName' => $model->file_name . '.' . $model->file_suffix,
                'fileExt' => $model->file_suffix
            ];
        }
        $this->addError(static::getFieldName($type), '保存记录失败');

        return false;
    }

    /**
     * 返回上传类型名称
     * @param $type integer 上传类型
     * @return mixed|string
     */
    public static function getFieldName($type)
    {
        $arr = [
            Attachment::AVATAR => 'imageFile',
            Attachment::IMAGE => 'imageFile',
            Attachment::VIDEO => 'videoFile',
            Attachment::AUDIO => 'audioFile',
            Attachment::OTHER => 'file',
        ];
        return isset($arr[$type]) ? $arr[$type] : '';
    }
}
